feat: support real-time append writes and reads with pluggable memory indexers - #163
feat: support real-time append writes and reads with pluggable memory indexers#163lxy-9602 wants to merge 5 commits into
Conversation
| } | ||
|
|
||
| std::vector<RealtimeCommitProgress> result; | ||
| for (const WriterSnapshot& snapshot : writer_snapshots) { |
There was a problem hiding this comment.
How should realtime writes recover if PrepareCommitWithProgress fails for
one bucket?
Terminating all bucket writers would make the failure scope too large for a
realtime workload. Could we preserve the prepared state of successful buckets
and retry or recreate only the failed bucket writer?
There was a problem hiding this comment.
Thanks for raising this concern. Bucket-level failure isolation is indeed valuable for long-running real-time workloads.
We checked the existing Paimon write path, including the Java Spark integration. Currently, FileStoreWrite.prepareCommit does not provide partial-success semantics across buckets. If preparing any bucket fails, the exception is propagated through TableWrite to the Spark data writer, causing the corresponding Spark task attempt to fail. Commit messages from buckets prepared earlier in the same call are not returned as independently recoverable results.
More generally, Paimon’s current read and write APIs do not define a contract for partial failure and partial recovery within one operation. For the first phase, we would prefer to keep the real-time implementation consistent with this existing behavior rather than introduce a separate recovery model only for PrepareCommitWithProgress.
For your use case, one practical approach is to use one FileStoreWrite instance per bucket. This keeps the failure scope local to that bucket: a failed bucket writer can be recreated and replayed independently, while writers for other buckets remain unaffected. A higher-level coordinator can still collect their commit messages and commit them under the desired snapshot boundary.
Bucket-level prepared-state preservation and retry could be considered as a future enhancement, but it would require a broader partial-recovery contract across Paimon’s read and write paths.
There was a problem hiding this comment.
Thanks for the clarification. This approach works for us.
We can use one FileStoreWrite per partition/bucket, recover a failed writer
independently, and let a higher-level coordinator collect the progress and
commit it under the same snapshot boundary.
Purpose
Linked issue: #158
This PR introduces an opt-in real-time write and read framework for fixed-bucket append tables.
Applications can attach a shared
RealtimeContextto write and scan contexts. Writes are buffered bya pluggable
MemIndexerand become queryable before snapshot commit. During prepare commit, thecurrent memory segment is sealed and flushed through Paimon's existing rolling writer, while later
writes continue in a new segment.
The read path captures an immutable memory view and combines it with the latest committed disk
snapshot through
RealtimeSplit. The append reader concatenates disk and memory readers, usingper-partition-bucket
_OFFSETprogress to avoid duplicate or missing rows.The main changes are:
MemIndexerandMemIndexerFactoryinterfaces.RealtimeContextfor sharing memory indexers between writers and readers.PrepareCommitWithProgressandCommitWithProgress.metadata/<uuid>.offsetsfiles.RefreshCommittedSnapshotto reclaim sealed memory covered by committed disk data.The current implementation supports streaming writes and latest-snapshot batch scans for fixed-bucket
append tables. Primary-key tables, deletion vectors, data evolution, streaming scans, scan-limit
pushdown, and global-index splits are not included in this PR.
Tests
Added unit coverage for:
Added 14 integration tests covering:
_OFFSETvalues;API and Format
This PR adds the following public API concepts:
RealtimeContextMemIndexer,MemIndexerFactory, andMemReadViewRealtimeWriteBatchandRealtimeCommitProgressWriteContextBuilder::WithRealtimeContextScanContextBuilder::WithRealtimeContextFileStoreWrite::PrepareCommitWithProgressFileStoreWrite::RefreshCommittedSnapshotFileStoreCommit::CommitWithProgressThe feature is opt-in through
RealtimeContext; existing write, commit, and disk-only read paths areunchanged when no real-time context is supplied.
Real-time data files contain the reserved
_OFFSETfield. Each committed snapshot references aversioned offsets file containing the latest offset for every partition-bucket. Data files and
offset progress are published atomically by the same snapshot commit.
Real-time commits currently fail directly on snapshot conflicts. Failure recovery and idempotent
retry will be handled separately.
Documentation
Generative AI tooling
Generated-by: OpenAI Codex (GPT-5)